#include <iostream>
#include <simulatorV1/dspSimulator/dspSimulator.h>
#include <simulatorV1/targetMachine/dspRegisterInfo.h>
#include <simulatorV1/type/type.h>
#include <simulatorV1/log/report.h>
#include <simulatorV1/instruction/mvk.h>
#include <simulatorV1/instruction/add.h>
#include <simulatorV1/instruction/mv.h>

DspSimulator::DspSimulator() {
    m_llvmJit = std::make_shared<LLVMJit>();
    m_parser = std::make_shared<Parser>();
}

void DspSimulator::run() {
    // 获取jit执行引擎
    auto ee = m_llvmJit->getExecutionEngine();
    // 初始化寄存器A0-A31,B0-B31
    initialRegisterInfo();
    // 添加模拟器支持的指令原型
    addInstructionProto();
    // 记录用户输入的命令
    std::string command;
    while (true) {
        Begin:
        fprintf(stdout, ">> ");
        fflush(stdout);
        std::cin >> command;

        // 如果输入q，退出程序
        if (command == "q" || command == "exit") {
            exit(0);
        }
        // 如果输入help，打印模拟器支持的指令格式
        if (command == "help") {
            u64 i = 1;
            // 遍历所有的指令原型，获取每个原型支持的指令格式并打印
            for (auto &proto: m_instProto) {
                auto formatStr = proto->formatToString();
                for (auto &str: formatStr) {
                    fprintf(stdout, "(%lu)\t%s\n", i++, str.c_str());
                }
            }
            continue;
        }

        // 如果输入A，打印寄存器A0-31
        for (auto name: RegAName) {
            if (command == name) {
                auto regPtr = (u32 *) ee->getGlobalValueAddress(command);
                fprintf(stdout, "%s:\t0X%08X\n", name, *regPtr);
                goto Begin;
            }
        }

        // 如果输入B，打印寄存器B0-31
        for (auto name: RegBName) {
            if (command == name) {
                auto regPtr = (u32 *) ee->getGlobalValueAddress(command);
                fprintf(stdout, "%s:\t0X%08X\n", name, *regPtr);
                goto Begin;
            }
        }
        // 语法分析器分析用户输入的命令，并获取分析得到的程序节点对象
        m_parser->analysis(command);
        auto programNode = m_parser->getProgramNode();
        // 根据程序节点生成ir函数
        std::string funcName = generateIRFunc(programNode);

        /// 调用生成的ir函数
        // 根据指令对应的IR函数名获取对应的函数地址
        auto funcAddr = (void *) ee->getFunctionAddress(funcName);
        // 如果函数不存在，打印错误
        if (!funcAddr) {
            fatalMacro(("jit执行引擎中不存在函数名：" + funcName).c_str());
        }
        // 如果函数存在，通过llvm jit执行该函数
        auto funcPtr = (void (*)()) (funcAddr);
        funcPtr();
    }
}

void DspSimulator::initialRegisterInfo() {
    // 初始化并获取一个寄存器模块
    m_llvmJit->initializeModule("register");
    auto registerModule = m_llvmJit->extraCurModule();
    // 获取ir生成器
    auto irBuilder = m_llvmJit->getIrBuilder();
    // 获取jit执行引擎
    auto ee = m_llvmJit->getExecutionEngine();
    // 创建并初始化全局变量A0-A31
    for (auto &name: RegAName) {
        registerModule->getOrInsertGlobal(name, irBuilder->getInt32Ty());
        auto value = registerModule->getNamedGlobal(name);
        value->setInitializer(llvm::ConstantInt::get(irBuilder->getInt32Ty(), 0));
        value->setLinkage(llvm::GlobalValue::ExternalLinkage);
    }
    // 创建并初始化全局变量B0-B31
    for (auto &name: RegBName) {
        registerModule->getOrInsertGlobal(name, irBuilder->getInt32Ty());
        auto value = registerModule->getNamedGlobal(name);
        value->setInitializer(llvm::ConstantInt::get(irBuilder->getInt32Ty(), 0));
        value->setLinkage(llvm::GlobalValue::ExternalLinkage);
    }
    // 将寄存器模块添加到jit执行引擎中
    ee->addModule(std::move(registerModule));
}

std::string DspSimulator::generateIRFunc(std::shared_ptr<ProgramNode> programNode) {
    static u64 i = 0;
    // 获取llvm上下文
    auto llvmContext = m_llvmJit->getLLVMContext();
    // 初始化一个模块，并获取该模块，之后的操作会在该模块中生成ir函数
    m_llvmJit->initializeModule(("module" + std::to_string(i)).c_str());
    auto funcModule = m_llvmJit->extraCurModule();
    // 获取ir生成器工具类
    auto irBuilder = m_llvmJit->getIrBuilder();
    // 获取jit执行引擎
    auto ee = m_llvmJit->getExecutionEngine();
    // 创建一个函数类型，类型为返回值void,无形参
    llvm::FunctionType *funcType = llvm::FunctionType::get(irBuilder->getVoidTy(), false);
    std::string funcName = "func" + std::to_string(i);
    // 根据函数类型创建函数
    llvm::Function *func = llvm::Function::Create(funcType, llvm::GlobalValue::ExternalLinkage, funcName,
                                                  funcModule.get());
    // 创建函数的入口基本块
    llvm::BasicBlock *entryBB = llvm::BasicBlock::Create(*llvmContext, "entry", func);
    // 设置ir生成的插入点为入口基本块
    irBuilder->SetInsertPoint(entryBB);
    // 创建ir函数前，创建所有寄存器的声明
    generateRegisterIRIntoModule(funcModule.get());
    // 生成ir函数
    for (auto &funcNode: programNode->m_functions) {
        generateInstructionIR(funcNode, funcModule.get());
    }
    // 函数返回值为void
    irBuilder->CreateRetVoid();

    // 如果定义了宏PRINT_FUNC，生成ir函数后打印该函数到控制台
#ifdef PRINT_FUNC
    funcModule->print(llvm::outs(), nullptr);
#endif
    // 将包含ir函数的ir模块添加到jit执行引擎中
    ee->addModule(std::move(funcModule));
    ++i;
    return funcName;
}

void DspSimulator::generateRegisterIRIntoModule(llvm::Module *module) {
    auto irBuilder = m_llvmJit->getIrBuilder();
    // 创建A0-A31寄存器的声明到模块module中
    for (auto &name: RegAName) {
        module->getOrInsertGlobal(name, irBuilder->getInt32Ty());
    }
    // 创建B0-B31寄存器的声明到模块module中
    for (auto &name: RegBName) {
        module->getOrInsertGlobal(name, irBuilder->getInt32Ty());
    }
}

void DspSimulator::generateInstructionIR(std::shared_ptr<FunctionNode> functionNode, llvm::Module *module) {
    // 遍历模拟器支持的指令原型，如果函数节点与某个指令原型匹配，调用generateIR生成指令对应的ir函数
    for (auto &proto: m_instProto) {
        if (proto->checkFormat(functionNode)) {
            proto->generateIR(functionNode, module, m_llvmJit->getIrBuilder());
        }
    }
}

void DspSimulator::addInstructionProto() {
    // 添加模拟器支持的指令原型
    m_instProto.emplace_back(std::make_shared<MVK>());
    m_instProto.emplace_back(std::make_shared<ADD>());
    m_instProto.emplace_back(std::make_shared<MV>());
}
